package ae.pcfc.cldos.online.common.manager.provider;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import ae.pcfc.cldos.online.common.clddb.domain.AttachmentType;
import ae.pcfc.cldos.online.common.clddb.domain.manager.SequencesDOM;
import ae.pcfc.cldos.online.common.etksdb.domain.Client;
import ae.pcfc.cldos.online.common.etksdb.domain.User;
import ae.pcfc.cldos.online.common.etksdb.domain.manager.UserDomainObjectManager;
import ae.pcfc.cldos.online.common.exception.FNPAppException;
import ae.pcfc.cldos.online.common.exception.PaymentException;
import ae.pcfc.cldos.online.common.manager.BaseManager;
import ae.pcfc.cldos.online.common.manager.FNPManager;
import ae.pcfc.cldos.online.common.manager.FileStorageManager;
import ae.pcfc.cldos.online.common.manager.GSEmployeeDetailsManager;
import ae.pcfc.cldos.online.common.tscdb.domain.TTscClientCompany;
import ae.pcfc.cldos.online.common.vo.FileVO;
import ae.pcfc.cldos.online.common.vo.fnp.FNPPaymentAdviceVO;
import ae.pcfc.cldos.online.fnp.ConstantsFNP;
import ae.pcfc.cldos.online.fnp.exception.FNPException;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPAccountTypeVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPCancelPaymentReqVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPCatalogVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPClientTypeVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPFinalPaymentResponseVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPGeneralInfoVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPParameterVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPPaymentAdviceReqVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPPaymentAdviceRspnsVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPPrepaidTransactionVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPReportReqVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPReportResponseVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPServicePaymentReqTypeVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPTransReportReqVO;
import ae.pcfc.cldos.online.fnp.service.client.vo.FNPTransReportResponseVO;
import ae.pcfc.cldos.online.net.service.vo.AttachmentVO;
import ae.pcfc.cldos.online.net.service.vo.InsertVoucherVO;

/**
 * @author akhader
 *
 */
public class FNPManagerImpl extends BaseManager implements FNPManager {

	private ae.pcfc.cldos.online.fnp.service.client.FinanceNPaymentFNP FinanceNPaymentFNP;
	private UserDomainObjectManager userDOM;
	private ae.pcfc.cldos.online.common.etksdb.domain.manager.ClientDOM clientDOM;
	private ae.pcfc.cldos.online.common.tscdb.domain.manager.TTscClientCompanyDOM tTscClientCompanyDOM;
	private SequencesDOM sequencesDOM;
	private FileStorageManager fileStorageManager;
	private GSEmployeeDetailsManager gsEmployeeDetailsManager;
	
	
	
	public GSEmployeeDetailsManager getGsEmployeeDetailsManager() {
		return gsEmployeeDetailsManager;
	}

	public void setGsEmployeeDetailsManager(
			GSEmployeeDetailsManager gsEmployeeDetailsManager) {
		this.gsEmployeeDetailsManager = gsEmployeeDetailsManager;
	}

	public void setFileStorageManager(FileStorageManager fileStorageManager) {
		this.fileStorageManager = fileStorageManager;
	}
	
	public SequencesDOM getSequencesDOM() {
		return sequencesDOM;
	}

	public void setSequencesDOM(SequencesDOM sequencesDOM) {
		this.sequencesDOM = sequencesDOM;
	}

	public void setUserDOM(UserDomainObjectManager userDOM) {
		this.userDOM = userDOM;
	}

	public ae.pcfc.cldos.online.common.etksdb.domain.manager.ClientDOM getClientDOM() {
		return clientDOM;
	}

	public void setClientDOM(
			ae.pcfc.cldos.online.common.etksdb.domain.manager.ClientDOM clientDOM) {
		this.clientDOM = clientDOM;
	}

	public ae.pcfc.cldos.online.common.tscdb.domain.manager.TTscClientCompanyDOM gettTscClientCompanyDOM() {
		return tTscClientCompanyDOM;
	}

	public void settTscClientCompanyDOM(
			ae.pcfc.cldos.online.common.tscdb.domain.manager.TTscClientCompanyDOM tTscClientCompanyDOM) {
		this.tTscClientCompanyDOM = tTscClientCompanyDOM;
	}

	public ae.pcfc.cldos.online.fnp.service.client.FinanceNPaymentFNP getFinanceNPaymentFNP() {
		return FinanceNPaymentFNP;
	}

	public void setFinanceNPaymentFNP(
			ae.pcfc.cldos.online.fnp.service.client.FinanceNPaymentFNP FinanceNPaymentFNP) {
		this.FinanceNPaymentFNP = FinanceNPaymentFNP;
	}
	/**
	 * @param trakhessID
	 * @return
	 */
	private FNPClientTypeVO getClientInfo(String userName){
		FNPClientTypeVO fnpClientTypeVO = new FNPClientTypeVO();
		//get user info
		User user = userDOM.findUserByUserName(userName);
		//call the method to fetch client
		Client client = clientDOM.getClientById(user.getClientId());
		//call method to fetch company
		TTscClientCompany tTscClientCompany = tTscClientCompanyDOM.getCompanyByTrakheesId(client.getCTrakheesId());
		fnpClientTypeVO.setId(tTscClientCompany.getCcTrakheesId());
		fnpClientTypeVO.setLicenseNumber(tTscClientCompany.getCcLicNo());
		fnpClientTypeVO.setNameAr(tTscClientCompany.getCcNameArb());
		fnpClientTypeVO.setNameEn(tTscClientCompany.getCcName());
		fnpClientTypeVO.setTrakheesID(client.getCTrakheesId());
		return fnpClientTypeVO;
	}
	/**
	 * @param userName
	 * @param appId
	 * @param tksID
	 * @param paymntAdviceNo
	 * @return
	 */
	private FNPGeneralInfoVO getFNPGenInfoVo(String userName,String appId, String tksID,String paymntAdviceNo){
		FNPGeneralInfoVO fnpGeneralInfoVO = new FNPGeneralInfoVO();
		fnpGeneralInfoVO.setClientId(tksID);
		fnpGeneralInfoVO.setPaymentAdviceNumber(paymntAdviceNo);
		fnpGeneralInfoVO.setTransactionNumber(generateTransactionNo());
		fnpGeneralInfoVO.setTransactionRemarks(ConstantsFNP.FNP_TRANSACTION_REMARKS);
		fnpGeneralInfoVO.setUserName(userName);
		return fnpGeneralInfoVO;
	}
	
	/**
	 * @param appId
	 * @param userName
	 * @param visaService
	 * @return
	 * @throws PaymentException 
	 */

	public FNPPaymentAdviceVO generatePayment(Long appId, String userName, String visaService,List<FNPParameterVO> fnpParams,String overLoadEmpCode,String clientRefNo) throws Exception{
		FNPPaymentAdviceReqVO fnpPaymentAdviceReqVO = new FNPPaymentAdviceReqVO();
		FNPClientTypeVO fnpClientTypeVO = getClientInfo(userName);
		fnpPaymentAdviceReqVO.setFnpClientTypeVO(fnpClientTypeVO);
		List<FNPServicePaymentReqTypeVO> fnpServicePaymentReqTypeVOs = new ArrayList<FNPServicePaymentReqTypeVO>();
		FNPServicePaymentReqTypeVO fNPServicePaymentReqTypeVO = new FNPServicePaymentReqTypeVO();
		fNPServicePaymentReqTypeVO.setQuantity(1);
		fNPServicePaymentReqTypeVO.setFnpParams(fnpParams);
		fNPServicePaymentReqTypeVO.setServiceId(visaService);
		fnpServicePaymentReqTypeVOs.add(fNPServicePaymentReqTypeVO);
		//add overload charges
		if(overLoadEmpCode!=null){
			FNPServicePaymentReqTypeVO overloadfNPServicePaymenteVO = new FNPServicePaymentReqTypeVO();
			overloadfNPServicePaymenteVO.setQuantity(1);
			overloadfNPServicePaymenteVO.setFnpParams(null);
			overloadfNPServicePaymenteVO.setServiceId(overLoadEmpCode);
			fnpServicePaymentReqTypeVOs.add(overloadfNPServicePaymenteVO);
		}
		fnpPaymentAdviceReqVO.setFnpServicePaymentReqTypeVOs(fnpServicePaymentReqTypeVOs);
		
		fnpPaymentAdviceReqVO.setRemarks(ConstantsFNP.FNP_REMARKS);
		fnpPaymentAdviceReqVO.setUserName(userName);
		fnpPaymentAdviceReqVO.setTransactionNumber(generateTransactionNo());
		fnpPaymentAdviceReqVO.setTransactionRemarks(ConstantsFNP.FNP_TRANSACTION_REMARKS);
		//call generate payment advice
		try{
			FNPPaymentAdviceRspnsVO fnpPaymentAdviceRspnsVO = FinanceNPaymentFNP.generatePaymentAdvice(fnpPaymentAdviceReqVO);
			//call block amount
			FinanceNPaymentFNP.blockAmount(getFNPGenInfoVo(userName, appId.toString(), fnpClientTypeVO.getTrakheesID(),fnpPaymentAdviceRspnsVO.getPaymentAdviceNumber()));
			//save the debit note to temp file storage
			FNPPaymentAdviceVO fnpPaymentAdviceVO = new FNPPaymentAdviceVO();
			mapper.map(fnpPaymentAdviceRspnsVO, fnpPaymentAdviceVO);
			
			InsertVoucherVO insertVoucherVO = new InsertVoucherVO();
			insertVoucherVO.setAdivceCreatedBy(userName);
			insertVoucherVO.setAdviceId(fnpPaymentAdviceRspnsVO.getPaymentAdviceNumber());
			insertVoucherVO.setApplicationId(clientRefNo);
			insertVoucherVO.setProcessStepCode("GENPV");
			gsEmployeeDetailsManager.insertPaymentAdvice(insertVoucherVO);
			
			FileVO fileVO = new FileVO();
			fileVO.setAttachmentTypeCode(AttachmentType.__ATTACHMENT_TYPE_PAYMENT_VOUCHER);
			fileVO.setInputStream(new ByteArrayInputStream(fnpPaymentAdviceRspnsVO.getPaymentAdvicePDF()));
			fileVO.setFileExt("pdf");
			fileVO.setFileName("Payment Voucher");
			fileVO.setUploadDate(new Date());
			fnpPaymentAdviceVO.setStoredPaymentAdvice(fileStorageManager.storeFile(fileVO, appId));
			
			return fnpPaymentAdviceVO;
		} catch (Exception e) {
			e.printStackTrace();
			throw new PaymentException(e);
		}
	}
	/**
	 * @param appId
	 * @param userName
	 * @param paymentAdviceNo
	 * @return
	 */
	public boolean cancelPayment(String appId,String userName,String paymentAdviceNo, boolean unblock){
		//call unblock amount
		if(unblock){
			FNPClientTypeVO fnpClientTypeVO = getClientInfo(userName);
			FinanceNPaymentFNP.unblockAmount(getFNPGenInfoVo(userName, appId, fnpClientTypeVO.getTrakheesID(),paymentAdviceNo));
		}
		//call cancel payment
		FNPCancelPaymentReqVO fnpCancelPaymentReqVO = new FNPCancelPaymentReqVO();
		fnpCancelPaymentReqVO.setPaymentAdviceNumber(paymentAdviceNo);
		fnpCancelPaymentReqVO.setMessage(ConstantsFNP.FNP_CANCEL_REMARKS);
		fnpCancelPaymentReqVO.setTransactionNumber(generateTransactionNo());
		fnpCancelPaymentReqVO.setUserName(userName);
		return FinanceNPaymentFNP.cancelPayment(fnpCancelPaymentReqVO);
	}
	
	public boolean cancelPayment(String appId,String userName,String paymentAdviceNo,String clientRefNo){
		boolean result = false;
		result =  cancelPayment(appId, userName, paymentAdviceNo, true);
		gsEmployeeDetailsManager.deactivatePaymentAdvice(clientRefNo, paymentAdviceNo);
		return result;
	}
	/**
	 * @param appId
	 * @param userName
	 * @param paymentAdviceNo
	 * @return
	 * @throws PaymentException 
	 * @throws IOException 
	 * @throws NumberFormatException 
	 */
	public FNPFinalPaymentResponseVO finalizePayment(String appId,String userName,String paymentAdviceNo) throws PaymentException, NumberFormatException, IOException{
		FNPFinalPaymentResponseVO finalPaymentResponseVO = new FNPFinalPaymentResponseVO();
		FNPClientTypeVO fnpClientTypeVO = getClientInfo(userName);
		FNPGeneralInfoVO fnpGeneralInfoVO = getFNPGenInfoVo(userName, appId, fnpClientTypeVO.getTrakheesID(),paymentAdviceNo);
		fnpGeneralInfoVO.setFnpClientTypeVO(fnpClientTypeVO);
		//call finalize payment
		try{
			finalPaymentResponseVO = FinanceNPaymentFNP.finalizePayment(fnpGeneralInfoVO);
		} catch (Exception e) {
			e.printStackTrace();
			throw new PaymentException(e);
		}
		FileVO fileVO = new FileVO();
		fileVO.setAttachmentTypeCode(AttachmentType.__ATTACHMENT_TYPE_DEBIT_NOTE);
		fileVO.setInputStream(new ByteArrayInputStream(finalPaymentResponseVO.getfNPDebitNoteVO().getDebitNotePDF()));
		fileVO.setFileExt("pdf");
		fileVO.setFileName("Debit Note");
		fileVO.setUploadDate(new Date());
		fileStorageManager.storeFileInNewTransaction(fileVO, Long.parseLong(appId));
		
		
		AttachmentVO attachmentVO = new AttachmentVO();
		attachmentVO.setApplicationID(appId);
		attachmentVO.setExtension(fileVO.getFileExt());
		attachmentVO.setFileName(fileVO.getFileName());
		attachmentVO.setFileType(fileVO.getAttachmentTypeCode());
		attachmentVO.setOnlineID(fileVO.getId().toString());
		finalPaymentResponseVO.setAttachmentVO(attachmentVO);
		
		return finalPaymentResponseVO;
	}
	/**
	 * @return transactionNo
	 */
	private String generateTransactionNo(){
		Long transactionNo = sequencesDOM.getNextFNPTransactionId();
		return ConstantsFNP.FNP_SOURCE+transactionNo.toString();
	}
	/**
	 * @param appId
	 * @param userName
	 * @param visaService
	 * @return
	 */
	public FNPPaymentAdviceRspnsVO previewPaymentAdvice(String userName, String visaService,List<FNPParameterVO> fnpParams,String overLoadEmpCode){
		FNPPaymentAdviceReqVO fnpPaymentAdviceReqVO = new FNPPaymentAdviceReqVO();
		FNPClientTypeVO fnpClientTypeVO = getClientInfo(userName);
		fnpPaymentAdviceReqVO.setFnpClientTypeVO(fnpClientTypeVO);
		List<FNPServicePaymentReqTypeVO> fnpServicePaymentReqTypeVOs = new ArrayList<FNPServicePaymentReqTypeVO>();
		FNPServicePaymentReqTypeVO fNPServicePaymentReqTypeVO = new FNPServicePaymentReqTypeVO();
		fNPServicePaymentReqTypeVO.setQuantity(1);
		fNPServicePaymentReqTypeVO.setFnpParams(fnpParams);
		fNPServicePaymentReqTypeVO.setServiceId(visaService);
		fnpServicePaymentReqTypeVOs.add(fNPServicePaymentReqTypeVO);
		//add overload charges
		if(overLoadEmpCode!=null){
			FNPServicePaymentReqTypeVO overloadfNPServicePaymenteVO = new FNPServicePaymentReqTypeVO();
			overloadfNPServicePaymenteVO.setQuantity(1);
			overloadfNPServicePaymenteVO.setFnpParams(null);
			overloadfNPServicePaymenteVO.setServiceId(overLoadEmpCode);
			fnpServicePaymentReqTypeVOs.add(overloadfNPServicePaymenteVO);
		}
		fnpPaymentAdviceReqVO.setFnpServicePaymentReqTypeVOs(fnpServicePaymentReqTypeVOs);
		fnpPaymentAdviceReqVO.setRemarks(ConstantsFNP.FNP_REMARKS);
		fnpPaymentAdviceReqVO.setUserName(userName);
		fnpPaymentAdviceReqVO.setTransactionNumber(generateTransactionNo());
		fnpPaymentAdviceReqVO.setTransactionRemarks(ConstantsFNP.FNP_TRANSACTION_REMARKS);
		//call generate payment advice
		FNPPaymentAdviceRspnsVO fnpPaymentAdviceRspnsVO = FinanceNPaymentFNP.previewPaymentAdvice(fnpPaymentAdviceReqVO);
		return fnpPaymentAdviceRspnsVO;
	}
	
	/**
	 * 
	 */
	public FNPAccountTypeVO enquireDeposits(String clentId){
		return FinanceNPaymentFNP.enquireDeposits(clentId);
	}
	
	/* (non-Javadoc)
	 * @see ae.pcfc.cldos.online.common.manager.FNPManager#retreiveFNPCatalog(java.util.List)
	 */
	public List<FNPCatalogVO> retreiveFNPCatalog(List<String> fnpServiceCodeList) throws FNPAppException{
		List<FNPCatalogVO> catalog = null;
		try{
			 catalog =  FinanceNPaymentFNP.retreiveFNPCatalog(fnpServiceCodeList); 
		}catch(Exception e){
			 e.printStackTrace();
			 throw new FNPAppException(e);
		}
		return catalog;
	}
	/**
	 * @param clientId
	 * @param startDate
	 * @param endDate
	 * @return
	 * @throws FNPException
	 */
	public List<FNPPrepaidTransactionVO> enquireDepositTransaction(String userName, Date startDate, Date endDate) {
		FNPClientTypeVO client = getClientInfo(userName);
		 return FinanceNPaymentFNP.enquireDepositTransaction(client.getId(), startDate, endDate);
	}
	/* (non-Javadoc)
	 * @see ae.pcfc.cldos.online.common.manager.FNPManager#generateClientAccountReport(ae.pcfc.cldos.online.fnp.service.client.vo.FNPReportReqVO)
	 */
	public FNPReportResponseVO generateClientAccountReport(String userName,Date startDate, Date endDate,String type,boolean actual){
		//get user info
		User user = userDOM.findUserByUserName(userName);
		//call the method to fetch client
		Client client = clientDOM.getClientById(user.getClientId());
		
		FNPReportReqVO fnpReportReqVO = new FNPReportReqVO();
		fnpReportReqVO.setEndDate(endDate);
		fnpReportReqVO.setStartDate(startDate);
		fnpReportReqVO.setTrakheesID(client.getCTrakheesId());
		fnpReportReqVO.setType(type);
		fnpReportReqVO.setActual(actual);
		
		return FinanceNPaymentFNP.generateClientAccountReport(fnpReportReqVO);
	}
	/**
	 * @param userName
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public List<FNPTransReportResponseVO> retreiveFNPTransactionReport(String userName,Date startDate, Date endDate){
		//get user info
		User user = userDOM.findUserByUserName(userName);
		//call the method to fetch client
		Client client = clientDOM.getClientById(user.getClientId());
		FNPTransReportReqVO fnpReportReqVO = new FNPTransReportReqVO();
		fnpReportReqVO.setEndDate(endDate);
		fnpReportReqVO.setStartDate(startDate);
		fnpReportReqVO.setTrakheesID(client.getCTrakheesId());
		
		return FinanceNPaymentFNP.retreiveFNPTransactionReport(fnpReportReqVO);
	}
}
